Hypercall to expose physical CPU information.
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 10 Nov 2009 13:03:42 +0000 (13:03 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 10 Nov 2009 13:03:42 +0000 (13:03 +0000)
It also make some changes to current cpu online/offline logic:
1) Firstly, cpu online/offline will trigger a vIRQ to dom0 for status
changes notification.
2) It also add an interface to platform operation to online/offline
physical CPU. Currently the cpu online/offline interface is in sysctl,
which can't be triggered in kernel. With this change, it is possible
to trigger cpu online/offline in dom0 through sysfs interface.

Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
xen/arch/x86/platform_hypercall.c
xen/arch/x86/smpboot.c
xen/arch/x86/x86_64/platform_hypercall.c
xen/include/asm-x86/smp.h
xen/include/public/platform.h
xen/include/public/xen.h

index 1dc0017a23b2d92a2cbdd219def7613888eb9689..5e4adb0b3775a5d7660d9e8ea455e1e56fb6d21c 100644 (file)
@@ -53,6 +53,12 @@ static long cpu_frequency_change_helper(void *data)
     return cpu_frequency_change(this_cpu(freq));
 }
 
+static long cpu_down_helper(void *data)
+{
+    int cpu = (unsigned long)data;
+    return cpu_down(cpu);
+}
+
 ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
 {
     ret_t ret = 0;
@@ -385,7 +391,97 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
             break;
         }
         break;
+
+    case XENPF_get_cpuinfo:
+    {
+        int i;
+        struct xenpf_pcpu_info *g_info;
+        struct xen_physical_cpuinfo pcpu;
+        XEN_GUEST_HANDLE(xen_physical_cpuinfo_t) g_cpus;
+
+        g_info = &op->u.pcpu_info;
+        if (g_info->info_num <= 0 )
+        {
+            op->u.pcpu_info.max_present = last_cpu(cpu_present_map);
+            op->u.pcpu_info.max_possible = last_cpu(cpu_possible_map);
+            goto done;
+        }
+
+        guest_from_compat_handle(g_cpus, g_info->info);
+
+        spin_lock(&cpu_add_remove_lock);
+
+        ret = -EFAULT;
+        for (i = 0; i < g_info->info_num; i++)
+        {
+            if (copy_from_guest_offset(&pcpu, g_cpus, i, 1) )
+                goto out;
+
+            if ( (pcpu.xen_cpuid >= NR_CPUS) ||
+                 (pcpu.xen_cpuid < 0) ||
+                 !cpu_present(pcpu.xen_cpuid) )
+            {
+                pcpu.flags |= XEN_PCPU_FLAGS_INVALID;
+            }
+            else
+            {
+                pcpu.apic_id = x86_cpu_to_apicid[pcpu.xen_cpuid];
+                pcpu.acpi_id = acpi_get_processor_id(pcpu.xen_cpuid);
+                ASSERT(pcpu.apic_id != BAD_APICID);
+                if (cpu_online(pcpu.xen_cpuid))
+                    pcpu.flags |= XEN_PCPU_FLAGS_ONLINE;
+            }
+
+            if ( copy_to_guest_offset(g_cpus, i, &pcpu, 1) )
+                goto out;
+        }
+        op->u.pcpu_info.max_present = last_cpu(cpu_present_map);
+        op->u.pcpu_info.max_possible = last_cpu(cpu_possible_map);
+        spin_unlock(&cpu_add_remove_lock);
+done:
+        ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
+    }
+    break;
+
+    case XENPF_resource_hotplug:
+    {
+        int cpu;
+
+        switch ( op->u.resource.sub_cmd)
+        {
+        case XEN_CPU_online:
+            cpu = op->u.resource.u.cpu_ol.cpuid;
+            if (!cpu_present(cpu))
+            {
+                ret = -EINVAL;
+                break;
+            }
+            else if (cpu_online(cpu))
+            {
+                ret = 0;
+                break;
+            }
+
+            ret = cpu_up(cpu);
+            break;
+        case XEN_CPU_offline:
+            cpu = op->u.resource.u.cpu_ol.cpuid;
+            if (!cpu_present(cpu))
+            {
+                ret = -EINVAL;
+                break;
+            } else if (!cpu_online(cpu))
+            {
+                ret = 0;
+                break;
+            }
+            ret = continue_hypercall_on_cpu(
+                0, cpu_down_helper, (void *)(unsigned long)cpu);
+            break;
+        }
+    }
+    break;
+
     default:
         ret = -ENOSYS;
         break;
index 99836ef65abe851b154d7a7b6640c97b43440492..045426818f8c86a12687b7c4b52ef7846ceef2ab 100644 (file)
@@ -44,6 +44,7 @@
 #include <xen/softirq.h>
 #include <xen/serial.h>
 #include <xen/numa.h>
+#include <xen/event.h>
 #include <asm/current.h>
 #include <asm/mc146818rtc.h>
 #include <asm/desc.h>
@@ -104,7 +105,7 @@ static void map_cpu_to_logical_apicid(void);
 DEFINE_PER_CPU(int, cpu_state) = { 0 };
 
 static void *stack_base[NR_CPUS];
-static DEFINE_SPINLOCK(cpu_add_remove_lock);
+DEFINE_SPINLOCK(cpu_add_remove_lock);
 
 /*
  * The bootstrap kernel entry code has set these up. Save them for
@@ -1342,6 +1343,8 @@ int cpu_down(unsigned int cpu)
        cpu_mcheck_distribute_cmci();
 
 out:
+    if (!err)
+        send_guest_global_virq(dom0, VIRQ_PCPU_STATE);
        spin_unlock(&cpu_add_remove_lock);
        return err;
 }
@@ -1362,6 +1365,8 @@ int cpu_up(unsigned int cpu)
                goto out;
 
 out:
+    if (!err)
+        send_guest_global_virq(dom0, VIRQ_PCPU_STATE);
        spin_unlock(&cpu_add_remove_lock);
        return err;
 }
index 2002900d61ec9a48b3ed510d034493a32d287f03..9a7a6e9faf24edb42c01b03b5b658a8fa0288e0d 100644 (file)
@@ -23,6 +23,12 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_op_t);
 #define xen_processor_power_t   compat_processor_power_t
 #define set_cx_pminfo           compat_set_cx_pminfo
 
+DEFINE_XEN_GUEST_HANDLE(compat_physical_cpuinfo_t);
+#define xen_physical_cpuinfo compat_physical_cpuinfo
+#define xen_physical_cpuinfo_t compat_physical_cpuinfo_t
+#define xenpf_pcpu_info compat_pf_pcpu_info
+#define xenpf_pcpu_info_t compat_pf_pcpu_info_t
+
 #define xenpf_enter_acpi_sleep compat_pf_enter_acpi_sleep
 
 #define COMPAT
index f94794930e36f5896fe6db1e10914a50d23fc8a7..066612c3a3906d35c859dd31062423aab3ab80ab 100644 (file)
@@ -56,6 +56,7 @@ extern u32 cpu_2_logical_apicid[];
 #define CPU_ONLINE     0x0002  /* CPU is up */
 #define CPU_DEAD       0x0004  /* CPU is dead */
 DECLARE_PER_CPU(int, cpu_state);
+extern spinlock_t(cpu_add_remove_lock);
 
 #ifdef CONFIG_HOTPLUG_CPU
 #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
index c69fdab8ad4a9ac3cbb5c502868c3aaa19b5d118..1a1cf0873b340fac1855c1df52ae1e3a6b2bc980 100644 (file)
@@ -312,6 +312,57 @@ struct xenpf_set_processor_pminfo {
 typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t;
 DEFINE_XEN_GUEST_HANDLE(xenpf_set_processor_pminfo_t);
 
+#define XENPF_get_cpuinfo 55
+struct xen_physical_cpuinfo {
+    /* IN */
+    uint32_t xen_cpuid;
+    /* OUT */
+    uint32_t apic_id;
+    uint32_t acpi_id;
+#define XEN_PCPU_FLAGS_ONLINE   1
+    /* Correponding xen_cpuid is not present*/
+#define XEN_PCPU_FLAGS_INVALID  2
+    uint32_t flags;
+    uint8_t  pad[128];
+};
+typedef struct xen_physical_cpuinfo xen_physical_cpuinfo_t;
+DEFINE_XEN_GUEST_HANDLE(xen_physical_cpuinfo_t);
+
+/*
+ * Fetch physical CPUs information
+ */
+struct xenpf_pcpu_info
+{
+    /* OUT */
+    /* The maxium cpu_id that is present */
+    uint32_t max_present;
+    /* The maxium possible cpus */
+    uint32_t max_possible;
+
+    /* IN */
+    uint32_t info_num;
+
+    XEN_GUEST_HANDLE(xen_physical_cpuinfo_t) info;
+};
+typedef struct xenpf_pcpu_info xenpf_pcpu_info_t;
+DEFINE_XEN_GUEST_HANDLE(xenpf_pcpu_info_t);
+
+struct xenpf_cpu_ol
+{
+    uint32_t cpuid;
+};
+
+#define XENPF_resource_hotplug 56
+struct xenpf_resource_hotplug {
+    uint32_t sub_cmd;
+#define XEN_CPU_online      1
+#define XEN_CPU_offline     2
+    union {
+        struct xenpf_cpu_ol   cpu_ol;
+        uint8_t               pad[64];
+    }u;
+};
+
 struct xen_platform_op {
     uint32_t cmd;
     uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -327,6 +378,8 @@ struct xen_platform_op {
         struct xenpf_change_freq       change_freq;
         struct xenpf_getidletime       getidletime;
         struct xenpf_set_processor_pminfo set_pminfo;
+        struct xenpf_pcpu_info          pcpu_info;
+        struct xenpf_resource_hotplug   resource;
         uint8_t                        pad[128];
     } u;
 };
index 0cd04728d9db5910ffb03495f2e9889c14871375..50692a03a48486b26e66d9e61af05d04adc88811 100644 (file)
@@ -145,6 +145,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
 #define VIRQ_DEBUGGER   6  /* G. (DOM0) A domain has paused for debugging.   */
 #define VIRQ_XENOPROF   7  /* V. XenOprofile interrupt: new sample available */
 #define VIRQ_CON_RING   8  /* G. (DOM0) Bytes received on console            */
+#define VIRQ_PCPU_STATE 9  /* G. (DOM0) PCPU state changed                   */
 
 /* Architecture-specific VIRQ definitions. */
 #define VIRQ_ARCH_0    16